package com.whosly.mysql.protocol.connection;

import com.whosly.mysql.protocol.code.IErrorCodeType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.AbstractMap;
import java.util.Map;

/**
 * @author fengyang
 * @date 2023/8/17 下午9:52
 * @see <a href="yueny09@163.com">mailTo: yueny09@163.com</a>
 */
public class ConnectionContextHolder
{

    /**
     * PID
     */
    private static final ThreadLocal<Long> PID = new ThreadLocal<>();

    /**
     * EXCEPTION:
     * <p>
     * key:   ErrorCodez
     * value: String errorMsg
     */
    private static final ThreadLocal<ExceptionBody> EX = new ThreadLocal<>();

    ////////////////////////////////////////////////////////////////
    //                      pid                                  //
    ////////////////////////////////////////////////////////////////
    /**
     * set PID
     */
    public static void set(final Long pid) {
        PID.set(pid);
    }

    /**
     * get PID
     */
    public static Long get() {
        return PID.get();
    }

    /**
     * remove PID
     */
    public static void remove() {
        PID.remove();
    }

    ////////////////////////////////////////////////////////////////
    //                      Exception                            //
    ////////////////////////////////////////////////////////////////

    /**
     * run failed, set Tuple<ErrorCodez, String>
     */
    public static void setException(final Map.Entry<IErrorCodeType, String> tuple) {
        setException(tuple.getKey(), tuple.getValue(), Boolean.FALSE);
    }

    /**
     * run failed or error
     */
    public static void setException(final IErrorCodeType errorCode, String errorMsg, boolean error) {
        EX.set(ExceptionBody.builder()
                .code(errorCode)
                .errorMsg(errorMsg)
                .isError(error)
                .build());
    }

    /**
     * get Tuple<ErrorCodez, String>
     */
    public static Map.Entry<IErrorCodeType, String> getException() {
        ExceptionBody t = getExceptionBody();
        if (t == null) {
            return null;
        }

        return new AbstractMap.SimpleEntry<>(t.getCode(), t.getErrorMsg());
    }

    private static ExceptionBody getExceptionBody() {
        return EX.get();
    }

    /**
     * remove Tuple<ErrorCodez, String>
     */
    public static void removeException() {
        ExceptionBody t = getExceptionBody();
        t = null;

        EX.remove();
    }

    /**
     * 是否出现异常
     */
    public static boolean hasException() {
        ExceptionBody t = getExceptionBody();
        if (t == null) {
            return false;
        }

        return t.isError;
    }

    ////////////////////////////////////////////////////////////////
    //                      removeALL                            //
    ////////////////////////////////////////////////////////////////

    /**
     * remove All Thread Local
     */
    public static void removeALL() {
        remove();
        removeException();
    }

    /**
     * 异常描述
     */
    @Builder
    @Getter
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    private static class ExceptionBody {
        private IErrorCodeType code;
        private String errorMsg;

        /**
         * true 为 error， false为run failed
         */
        private Boolean isError;
    }
}
